package org.flowers.unbeaten.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.flowers.unbeaten.base.entity.BaseEntity;
import org.flowers.unbeaten.base.entity.Role;
import org.flowers.unbeaten.base.entity.RoleMenu;
import org.flowers.unbeaten.base.entity.UserRole;
import org.flowers.unbeaten.base.vo.MenuVo;
import org.flowers.unbeaten.base.vo.RolePermissionVo;
import org.flowers.unbeaten.exception.BusinessException;
import org.flowers.unbeaten.exception.code.BaseResponseCode;
import org.flowers.unbeaten.mapper.RoleMapper;
import org.flowers.unbeaten.service.IMenuService;
import org.flowers.unbeaten.service.IRoleMenuService;
import org.flowers.unbeaten.service.IRoleService;
import org.flowers.unbeaten.service.IUserRoleService;
import org.flowers.unbeaten.util.HttpSessionUtils;
import org.flowers.unbeaten.util.Id;
import org.flowers.unbeaten.util.PageUtils;
import org.flowers.unbeaten.util.PageVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色 服务实现类
 * </p>
 *
 * @author RyanWang
 * @since 2021-07-15
 */
@Slf4j
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private IRoleService roleService;

    @Autowired
    private IUserRoleService userRoleService;

    @Autowired
    private IRoleMenuService roleMenuService;

    @Autowired
    private IMenuService menuService;

    @Autowired
    private HttpSessionUtils httpSessionUtils;

    @Override
    public PageVo<Role> getRolePageList(Role role, BaseEntity baseEntity) {
        PageHelper.startPage(baseEntity.getPage(), baseEntity.getLimit());
        List<Role> roles = roleMapper.selectRoles(role);
        return PageUtils.getPageVo(roles);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(Role role) {
        Role one = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getRoleName, role.getRoleName()));
        if (Objects.nonNull(one)) {
            throw new BusinessException(BaseResponseCode.DATA_ALREADY_EXISTS);
        }
        role.setRoleId(Id.generateId());
        roleMapper.insert(role);
        if (!CollectionUtils.isEmpty(role.getPermissions())) {
            RolePermissionVo vo = new RolePermissionVo();
            vo.setRoleId(role.getRoleId());
            vo.setPermissions(role.getPermissions());
            roleMenuService.add(vo);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(Role role) {
        Role source = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getRoleId, role.getRoleId()));
        if (!source.getRoleName().equals(role.getRoleName())) {
            Role one = roleService.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getRoleName, role.getRoleName()));
            if (Objects.isNull(one)) {
                throw new BusinessException(BaseResponseCode.DATA_ALREADY_EXISTS);
            }
        }
        role.setUpdateTime(LocalDateTime.now());
        roleMapper.updateById(role);
        // 删除角色绑定的权限关系
        roleMenuService.remove(Wrappers.<RoleMenu>lambdaQuery().eq(RoleMenu::getRoleId, role.getRoleId()));
        if (!CollectionUtils.isEmpty(role.getPermissions())) {
            RolePermissionVo vo = new RolePermissionVo();
            vo.setRoleId(role.getRoleId());
            vo.setPermissions(role.getPermissions());
            roleMenuService.add(vo);
            // 刷新权限
            httpSessionUtils.refreshRolePermission(role.getRoleId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<String> ids) {
        for (String id : ids) {
            // 获取关联的用户ID
            List<String> userIds = userRoleService.getUserIdsByRoleId(id);
            // 删除角色
            roleService.removeById(id);
            // 删除角色绑定的权限数据
            roleMenuService.remove(Wrappers.<RoleMenu>lambdaQuery().eq(RoleMenu::getRoleId, id));
            // 删除角色和用户的关联数据
            userRoleService.remove(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getRoleId, id));
            if (!CollectionUtils.isEmpty(userIds)) {
                // 刷新权限
                userIds.parallelStream().forEach(httpSessionUtils::refreshUerId);
            }
        }
    }

    @Override
    public Role detail(String roleId) {
        Role role = roleService.getById(roleId);
        if (Objects.isNull(role)) {
            log.error("传入的roleId:{}不合法");
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        List<MenuVo> menuVoList = menuService.getAllTree();
        LambdaQueryWrapper<RoleMenu> wrapper = Wrappers.<RoleMenu>lambdaQuery().select(RoleMenu::getMenuId).eq(RoleMenu::getRoleId, role.getRoleId());
        Set<Object> checkList = new HashSet<>(roleMenuService.listObjs(wrapper));
        setChecked(menuVoList, checkList);
        role.setMenuVos(menuVoList);
        return role;
    }

    private void setChecked(List<MenuVo> list, Set<Object> checkList) {
        for (MenuVo vo : list) {
            if (checkList.contains(vo.getMenuId()) && CollectionUtils.isEmpty(vo.getChildren())) {
                vo.setChecked(true);
            }
            setChecked((List<MenuVo>) vo.getChildren(), checkList);
        }
    }

    @Override
    public List<Role> getRoleByUserId(String userId) {
        List<String> roleIds = userRoleService.getRoleIdsByUserId(userId);
        if (CollectionUtils.isEmpty(roleIds)) {
            return null;
        }
        return roleMapper.selectBatchIds(roleIds);
    }

    @Override
    public List<String> getRoleNames(String userId) {
        List<Role> roles = getRoleByUserId(userId);
        if (CollectionUtils.isEmpty(roles)) {
            return null;
        }
        return roles.stream().map(Role::getRoleName).collect(Collectors.toList());
    }
}
